package com.itcast.peft.service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.itcast.peft.config.MultipleModelConfig.ChatModelHolder;
import com.itcast.peft.entity.Question;
import com.itcast.peft.mapper.QuestionMapper;
import com.itcast.peft.service.InteractionDataWasher.WashedData;
import com.itcast.peft.util.AsyncWrapper;
import com.itcast.peft.util.ExceptionWrapper;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class QuestionService {

    /**
     * 数据量较大，起并发
     */
    @Autowired
    private AsyncWrapper asyncWrapper;

    @Autowired
    private QuestionMapper mapper;

    private ChatClient chatClient;

    @Autowired
    @Qualifier("distillQuestionModelHolder")
    private ChatModelHolder questionModelHolder;

    @PostConstruct
    void init() {
        this.chatClient = ChatClient.builder(questionModelHolder.getModel())
                .defaultSystem("你是一个计算机领域和教育领域的专家").build();
    }

    @Async
    public void generateQuestion() {
        var batchId = new String[] { UUID.randomUUID().toString(), UUID.randomUUID().toString() };
        var futureList = Stream
                .<Runnable>of(
                        () -> generate(batchId, "请给出40个有关Java的国内大厂常见面试题，范围是为Java基础，题目之间允许有一定重合度，不包括中间件，不用写序号，使用中文输出"),
                        () -> generate(batchId, "请给出40个有关Spring中间件的国内大厂常见面试题，围绕Spring基础和SpringCloud生态，题目之间允许有一定重合度，不用写序号，使用中文输出"),
                        () -> generate(batchId, "请给出40个有关MySql的国内大厂常见面试题，题目之间允许有一定重合度，不用写序号，使用中文输出"),
                        () -> generate(batchId, "请给出40个有关Redis的国内大厂常见面试题，题目之间允许有一定重合度，不用写序号，使用中文输出"),
                        () -> generate(batchId, "请给出40个有关MQ的国内大厂常见面试题，包括Kafka、RocketMQ等常见类型，题目之间允许有一定重合度，不用写序号，使用中文输出"))
                .map(r -> CompletableFuture.runAsync(r, this.asyncWrapper.getExecutor())).toList();

        futureList.forEach(ExceptionWrapper.<CompletableFuture<Void>, Void>wrapToRTE(CompletableFuture::get)::apply);

        log.info("question generated:{}", Arrays.deepToString(batchId));
    }
    
    public void addWashedData(List<WashedData> data) {
        var batchId = UUID.randomUUID().toString();
        var qList = data.stream().map(w -> {
            Question generated = new Question();
            generated.setBatchId(batchId);
            generated.setQuestion(w.getInteractionQuestion().getDescription());
            w.setTargetQuestion(generated);
            return generated;
        }).toList();
        var inserted = mapper.insert(qList);
        log.info("washed data inserted:{} with batchId:{}", inserted, batchId);
    }
    
    public void addPDFDataAsQuestion(List<String> strFromPDF) {
        var batchId = UUID.randomUUID().toString();
        var qList = strFromPDF.stream().map(s -> {
            Question generated = new Question();
            generated.setBatchId(batchId);
            generated.setQuestion(s);
            return generated;
        }).toList();
        var inserted = mapper.insert(qList);
        log.info("strFromPDF data inserted:{} with batchId:{}", inserted.size(), batchId);
    }
    
    public byte[] toVolcesBatchformat() throws IOException {
        var all = mapper.selectList(null);
        var assistant = "你是一个计算机领域的教育专家，你须要对学生提问的题目输出一份标准答案,在你的回答中除了包含正确答案外，还需要结合题目考虑如下内容：1.题目的思路解析 2.题目的考察点解析 3.适当的举例子 4.答案中不用对你自己的身份进行说明，专心输出标准答案";

        var template = "{\"custom_id\": \"%s\", \"body\": {\"messages\": [{\"role\": \"system\", \"content\": \"%s\"},{\"role\": \"user\", \"content\": \"%s\"}] }}";
        try (ByteArrayOutputStream bios = new ByteArrayOutputStream()) {
            all.forEach(q -> {
                var json = String.format(template, String.valueOf(q.getId()), assistant, q.getQuestion()) + '\n';
                bios.writeBytes(json.getBytes());
            });
            // 输出数据为下载文件的形式
            return bios.toByteArray();
        }
    }

    private void generate(String[] batchId,String msg) {
        var lst = chatClient.prompt()
                .user(msg + "\n你需要返回一个合法的JsonArray格式")
                .call().entity(new ParameterizedTypeReference<List<String>>() {
        });
        Collections.shuffle(lst);
        var parted = Lists.partition(lst, lst.size() / batchId.length);
        for (int i = 0; i < batchId.length; i++) {
            var bId = batchId[i];
            var qlist = parted.get(i).stream().map(s -> {
                Question generated = new Question();
                generated.setBatchId(bId);
                generated.setQuestion(s);
                return generated;
            }).toList();
            var inserted = mapper.insert(qlist, 100);
            log.info("generated data inserted:{}", inserted);
        }
    }
}
